Skip to content

Conversation

@disconcision
Copy link
Member

@disconcision disconcision commented Feb 5, 2026

Potemkin modules. Cargo modules. I can believe theyre not modules. Subsumes #2075.

disconcision and others added 30 commits December 22, 2025 00:56
Re-add features that were simplified for probemoar merge:

Debug/profiling (for development):
- WorkerServer.re: Eval timing logging
- ScratchMode.re: Round-trip timing
- CodeEditable.re: Probe perf profiling

UI features:
- NutMenu.re: probe_all toggle enabled
- ProbeSidebar.re: Full feature set
  - Probearium/Printarium mode toggle
  - sketch_view settings panel with all toggles
  - Full Dynamic Cursor with opacity for items after index
  - Sample displays in probe list
  - indicated-call red outline

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The fold projector's hover view was always rendering code as single-line
because simple_code hardcoded is_single_line=true. Now view_seg accepts
an optional ~single_line parameter (default false) so FoldProj gets
multiline display while ProbeProj and TypeProj explicitly use single-line.

Changes:
- ProjectorBase.re: Add ~single_line to View.seg type
- ProjectorView.re: Pass ~single_line through flex_code and mk_view
- ProbeProj.re: Create view_seg_single_line wrapper for probe displays
- TypeProj.re: Add ~single_line=true for type display
- ProbeSidebar.re: Add ~single_line=true for sidebar displays

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Each legend item now shows an explanatory tooltip on hover,
positioned below the legend panel. Also cleans up Language
module prefixes in ProbeSidebar.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When a sample has no environment bindings to display, the context menu
actions (Pin/Step into) now stack vertically like a traditional menu
instead of horizontally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Merges latest dev changes and resolves conflicts:
- ZipperBase.re: Use dev's extracted Refractor module pattern
- Editor.re: Keep dev's comment, add auto_def probe handling
- Refractors.re (root): Deleted, functionality moved to ProbePerform.re

Adds auto_def field to zipper/Refractors.re for auto-probe-follows-cursor
feature, which automatically places an auto-probe on the body of whichever
top-level definition the cursor is currently inside.

Fixes data flow issue where probes would appear but show no samples until
an edit was made. The fix detects ephemeral probe changes in CodeWithStatics
and triggers statics recalculation, which updates evaluation targets.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When the cursor is on a secondary (whitespace/comment), the indicated
piece has no statics info, causing toplevel_def_body_id to return None.

Fix: Fall back to using the parent tile's ID from the zipper's ancestors,
which is guaranteed to be a real tile with statics info.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Two new auto-probe behaviors:

1. Test forms: When cursor is inside a test, auto-probe the entire test
   body. This overrides let behavior, so `test let a = 1 in a pass` with
   cursor on `a` probes the full test body, not just the let definition.

2. Let delimiter/pattern: When cursor is on the let keyword itself or
   inside the pattern (not in body), auto-probe the definition.

Implementation:
- StaticsBase.toplevel_def_body_id: Check for Test/HintedTest as current
  term or ancestor (priority over Let). Changed Let condition from
  "cursor in def" to "cursor NOT in body".
- ProbePerform.target_subterm_ids: Don't redirect Let→definition when
  the Let is the body of a Test (so we see test result, not just def).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Rewrote toplevel_def_body_id with a cleaner top-down algorithm:
- Walk ancestors from outermost to innermost
- For each let, check if child-toward-cursor is the body
- If child == body: skip (cursor in body, let doesn't apply)
- Otherwise: return that let's def (cursor in def/pattern/on-delimiter)

Key insight: the ONLY way to not probe a let's def is if cursor is
in its body. Being on the delimiter, pattern, or def all qualify.

Fixed edge case: when cursor is directly on a top-level let (no
containing let exists), return that let's def as the auto-probe target.

Also moved toplevel_def_body_id from StaticsBase.re to ProbePerform.re
since it's probe-specific logic, not general statics.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Brings in:
- Auto-probe for test forms and let delimiters/patterns
- Fix auto-probe disappearing on whitespace/comments
- Top-down algorithm for toplevel_def_body_id
- Move toplevel_def_body_id from StaticsBase to ProbePerform
…toprobe when active. manual run more for printarium / console log
When a probe (manual or auto) is added, the sample cursor now
automatically points to an appropriate sample from that probe once
evaluation completes. Uses pending_probe_cursor field to defer until
async worker returns results. Picks the lexically first probe with
samples and uses closest_to_cursor for conservative sample selection.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- TyDi: min 2-char prefix before showing completions; prioritize
  keywords over context vars when expected type is unknown
- AutoProbe: soft-reject function types (probe if no better alternative)
- Elaborator: elaborate first pattern in MultiHole([Pat(p1), ...])
- Abbreviate: show <function> and builtin name instead of <>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When inserting a tile, select a mold appropriate for the local sort
context rather than just taking the first available mold. This prevents
wrong-sort molds (e.g., Exp mold for `-` in a Pat context) from being
assigned during insertion.

- Form.Molds: split into get_base, try_get (strict), try_get_permissive,
  and get (with fallback). Strict filtering for remolding, permissive
  for insertion (allows wrong-sort multi-delimiter forms to expand)
- Relatives.sort: compute local sort at insertion point from left
  sibling's right nib (handles heterogeneous infix like `:`)
- Insert.re: use sort-aware Form.Molds.get
- Segment.remold_tile: use strict try_get
- Ancestor.re: remove unused functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Expansion now considers sort context when deciding how to expand
delimiters. This prevents wrong-sort expansions (e.g., `let` expanding
in Pat context) and enables sort-specific forms (e.g., `[` expanding
to ListLitPat vs ListLitExp based on context).

Key changes:
- Form.re: Register expansions using nib sort (the context you're
  typing in) rather than mold.out (what the form produces). Rul
  context is permissive and falls back to any expansion since rules
  contain Exp/Pat operands but have no operand forms of their own.
- Insert.re: Handle `|` entirely here when inside case expressions,
  bypassing sort-specific lookup. This is needed because ascriptions
  (expr : Type) have Typ right nib even though they produce Exp.
- TyDiForms.re: Pass sort to Form.Expansion.get.

See plans/sort-specific-expansion.md for detailed analysis of the
case/rule structure and known limitations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When moving to a function definition with auto-probe mode enabled,
the sample cursor wasn't being set correctly - samples appeared blue
until another action was performed.

Fixes:
- CellEditor: Pass ~auto_probe_mode to second pass in calculate to
  prevent clear_auto_def from removing the probe
- CellEditor: Force recalculation when pending_probe_cursor is set
  during ResultAction handling
- Editor: Call resolve_pending_probe_cursor after update_auto_def_probe
  since editor_effects runs before it

Also:
- ProbeSidebar: Shorten toggle labels ("Auto"/"Manual" -> "A"/"M")
- Test: Fix arrow syntax in recursive test case
- TODO: Commented out profiling code in CodeEditable, WorkerServer,
  ScratchMode (to be deleted later)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- New ClosureCursorBar component shows call stack as breadcrumbs
- Appears below top bar when probes are active
- Click entries to jump to syntax location
- Add RecordStackFrame to built-in function applications
- Fix grid layout for 4-row structure with sidebars

Co-Authored-By: Claude Opus 4.5 <[email protected]>
disconcision and others added 22 commits February 4, 2026 13:27
- plans/modules-phase-1.md: Detailed implementation plan for Phase 1 modules
- claude.md: Worktree session tracking for parallel development

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add Mod sort for module-level items
- Add module forms: ModBody, ModSeq, ModLet, ModType
- Add mk_pre' helper for heterogeneous prefix forms (body sort differs from out)
- Add MakeTerm parsing for modules with semicolon sequence flattening
- Add remold_mod function with Exp fallback for bare expressions
- Add CSS styling for Mod sort (greenish color)
- Add Module(list(Mod.t)) to exp_term for module expressions
- Add stubs in dynamics/statics for Module expression type

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- In Insert.re: When in Mod context and no Mod expansion exists, try Exp
  (allows if/test/etc forms to expand inside module bodies)
- Updated modules-phase-1.md with comprehensive implementation notes:
  - Heterogeneous prefix forms (mk_pre')
  - Mod→Exp fallback pattern for remolding and expansion
  - Sort disambiguation at heterogeneous boundaries
  - Decision table for sort resolution
  - Future considerations (universal semicolon, removing CellJoin)
- Removed plans/sort-disambiguation-phase-1.1.1.md (content integrated)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Phase 1.2: Module expansion and semantics (ExpandModule.re, Statics, Elaborator)
- Phase 1.3: Menhir parser support
- Phase 1.4: Comprehensive testing (parsing, statics, dynamics, grammar factory)
- Phase 1.5: Polish and exploration (empty module, ExplainThis, other systems)
- Phase 1.6: Final report documentation

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Module expansion:
- ExpandModule.re: Transform module syntax into nested let/type + labeled tuple
- Statics.re: Type-check modules by expanding and checking expanded form
- Elaborator.re: Elaborate modules directly to expanded form

Menhir parser:
- AST.re: Add Module and mod_item types
- Lexer.mll: Add OPEN_CURLY and CLOSE_CURLY tokens
- Parser.mly: Add modItem rule and module expression grammar
- Conversion.re: Add ModItem conversion functions
- Grammar.re: Add mod_ type alias for Factory module

Also includes formatting fixes from dune fmt.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Statics tests:
- Empty module
- Single and multiple bindings
- Shadowing behavior
- Type aliases
- Bare expressions
- Module access via dot notation
- Module as labeled tuple

Evaluator tests:
- Module evaluation to labeled tuple
- Access via dot notation
- Sequential bindings
- Type aliases
- Shadowing

2 tests skipped for features not yet fully working:
- Nested modules
- Module with function binding access

All 1446 tests pass.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Mark all implemented phases as complete:
- Phase 1.1: Syntax foundation ✅
- Phase 1.2: Module expansion & semantics ✅
- Phase 1.3: Menhir parser ✅
- Phase 1.4: Testing ✅

All 1446 tests pass. 2 tests skipped for features not yet fully working.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Fixes:
- Empty module atomic form: {} now creates atomic EmptyModule token
  (like () and []) instead of compound form with hole. Added {} to
  Token.is_potential_token and EmptyModule to Form.re atomic forms.

- Singleton labeled tuple pattern bug: Fixed incorrect elaboration
  when Var pattern has Unknown synth type. Now only elaborates
  (destructures) if pattern name matches the tuple label.
  e.g., `let m = (y=1) in m` now correctly has type (y=Int), not Int.

Documentation:
- Added detailed Menhir parser section explaining semicolon ambiguity
  (shift-reduce conflict between Seq and module item separator) and
  potential fix options (grammar duplication, GLR, lexer hack, etc.)

- Replaced incomplete "Capitalized Names in Patterns" section with
  comprehensive "Capitalized Module Names: Design Considerations"
  covering both pattern/binding AND expression/reference sides,
  with analysis of 5 options and trade-offs. Decision deferred.

Tests:
- All 1461 tests pass
- Added nested module tests to Test_MakeTerm.re
- Expanded statics and evaluator module tests

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Added section explaining why cursor inspector does not work for module items
(fresh IDs in expansion) and the solution: preserve Mod item IDs on wrapper
Let/TyAlias expressions using IdTagged.mk_internal. This also unifies Statics
and Elaborator since both can use the same deterministic expansion.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit enables cursor inspector support for module constructs by:

1. Preserving IDs on wrapper expressions during module expansion:
   - ModLet ID → wrapper Let expression
   - ModType ID → wrapper TyAlias expression
   - ModExp uses fresh ID (synthetic, inner expr has its own IDs)

2. Absorbing semicolon IDs in MakeTerm (like ListLit absorbs comma IDs):
   - Module expression now includes semicolon IDs from inner Mod sequence
   - Enables cursor inspector to show info for both braces and semicolons

3. Using fresh IDs for the final labeled tuple:
   - Prevents overwriting Module statics map entry
   - Avoids infinite loops in Elaborator

Key insight: ModExp differs from ModLet/ModType - it wraps an existing
expression that already has its own IDs. The synthetic let _ = e wrapper
needs a fresh ID to avoid conflicts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
MakeTerm changes:
- Use is_mod_seq to handle any number of semicolons (not just 2 items)
- Only absorb IDs when body is MultiHole (avoids duplicating single-item IDs)
- Fixes infinite loop that occurred with single-item modules

Known limitation documented in plan:
- Only first semicolon has cursor info due to nested Skel structure
- Inner semicolon IDs are buried in nested MultiHole annotations
- flatten_mod flattens terms but not IDs
- Documented potential solutions: modify Skel, collect IDs during flatten, or accept limitation

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add semicolons to is_chainable when both tiles have mold.out == Sort.Mod.
This produces flat Bin structures for module semicolons (like commas do for
tuples), instead of nested binary structures. CellJoin (Exp-sort semicolons)
is unaffected due to the Sort.Mod guard.

Flat structure means is_mod_seq in MakeTerm sees all semicolons at once,
which is prerequisite for collecting all semicolon IDs for cursor inspector.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
With flat Skel structure (from previous commit), body.annotation.ids now
contains ALL semicolon IDs for multi-item modules. The existing MultiHole
absorption path in MakeTerm naturally handles this - no additional ID
collection logic needed. Updated comments to reflect the new reality.

Plan updates:
- Documented Skel fix resolving the nested semicolon ID issue
- Added near-term item: module semicolon decoration is visually noisy
  (arms drawn between all semicolons), consider custom decoration

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add signature (Sig) sort for module type annotations:
- Sig sort infrastructure parallel to Mod (Sort, Grammar, Form,
  Segment, Skel, Arms, Insert, MakeTerm)
- Sig as Typ variant with desugar_sig bridge to labeled tuples
- Type-directed module expansion for error attribution
- Cursor inspector integration (Mod/Sig cls, colors, bolding)
- Menhir parser support for Sig syntax
- ExpToSegment: full Module and Sig pretty-printing with whitespace
- Sig pretty_print in Typ.re for cursor inspector display
- Module abbreviation in Abbreviate.re

Tests added across 8 test files (1502 total, all pass):
- 14 statics, 11 evaluator, 4 elaboration, 6 ExpToSegment roundtrip,
  4 editing, 2 abbreviation, 5 Menhir Sig roundtrip tests

Bug fixes:
- ExpToSegment: wrap mod/sig items with secondary for whitespace
- ExpToSegment: ModType mk_form children count (1 inner sort, not 2)
- Typ.re: Sig pretty_print renders { let x : Int } not {sig}
- Abbreviate.re: recursive module item abbreviation

Docs and plans consolidated.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Module width mismatches (sig wider/narrower than module) now produce
type errors. The fix builds the actual Prod type from the module's
exported bindings rather than using expanded_info.ty, which masked
width errors via fixed_typ_exp.

Empty module signatures ({} in type position) now parse correctly
as Sig([]) by adding a Typ mold to the EmptyModule atomic form.

Adds 16 new statics tests covering sig annotations, width errors,
and module/tuple equivalence limitations. Updates modules doc slide.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@disconcision disconcision changed the title Modules I Baby Modules Feb 8, 2026
@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 41.50794% with 737 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.03%. Comparing base (062397c) to head (33ae5d1).
⚠️ Report is 3 commits behind head on dev.

Files with missing lines Patch % Lines
src/haz3lcore/ProbePerform.re 4.95% 96 Missing ⚠️
src/haz3lcore/tiles/Segment.re 43.75% 72 Missing ⚠️
.../haz3lcore/projectors/implementations/ProbeProj.re 0.00% 67 Missing ⚠️
src/language/term/Typ.re 37.20% 54 Missing ⚠️
src/language/term/Grammar.re 34.32% 44 Missing ⚠️
src/haz3lcore/pretty/ExpToSegment.re 53.24% 36 Missing ⚠️
src/language/term/TermBase.re 25.58% 32 Missing ⚠️
src/haz3lcore/lang/MakeTerm.re 67.05% 28 Missing ⚠️
src/language/term/Equality.re 44.00% 28 Missing ⚠️
src/language/statics/Statics.re 62.50% 21 Missing ⚠️
... and 38 more
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #2104      +/-   ##
==========================================
- Coverage   50.40%   50.03%   -0.37%     
==========================================
  Files         230      233       +3     
  Lines       25365    26466    +1101     
==========================================
+ Hits        12784    13243     +459     
- Misses      12581    13223     +642     
Files with missing lines Coverage Δ
src/haz3lcore/derived/AutoProbe.re 71.57% <100.00%> (+0.83%) ⬆️
src/haz3lcore/lang/Precedence.re 94.23% <ø> (ø)
src/haz3lcore/lang/Token.re 81.81% <100.00%> (+0.56%) ⬆️
src/haz3lcore/tiles/Mold.re 60.97% <100.00%> (+0.97%) ⬆️
src/haz3lcore/zipper/Ancestor.re 75.00% <ø> (+26.61%) ⬆️
src/haz3lcore/zipper/Relatives.re 78.78% <100.00%> (+2.38%) ⬆️
src/language/dynamics/Evaluator.re 94.36% <ø> (+0.08%) ⬆️
src/web/app/editors/code/CodeEditable.re 0.00% <ø> (ø)
src/web/init/Init.re 57.14% <ø> (ø)
src/web/view/NutMenu.re 0.00% <ø> (ø)
... and 48 more

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@disconcision disconcision changed the base branch from sorted-insertion to dev February 9, 2026 07:04
@disconcision disconcision changed the base branch from dev to probe-III February 9, 2026 07:06
@disconcision disconcision changed the base branch from probe-III to dev February 9, 2026 07:08
disconcision and others added 2 commits February 10, 2026 13:52
In Mod/Sig sort context, concave grout now uses mod_seq precedence
(very loose) instead of concave_grout (tight). This means deleting a
semicolon between module items leaves them as separate items rather
than absorbing everything into one broken expression body.

Threaded via optional ~sort parameter on Skel.mk and Segment.skel,
defaulting to Exp. MakeTerm passes the child sort from tile molds.

Also makes flatten_mod/flatten_sig handle non-Mod/Sig children in
multi-holes by wrapping them as module items, isolating parse breakage.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@cyrus-
Copy link
Member

cyrus- commented Feb 11, 2026

Async_kernel: Unhandled exception (Failure "ExplainThis: Secondary Impossible")

not sure what I did, clicked on something

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants